﻿using System;
using System.Drawing;
using System.Threading;
using System.Timers;

namespace Tetris
{
    class Palette
    {
        private int _width = 15; //画板宽度
        private int _height = 25; //画板高度
        private Color[,] coorArr; //固定方块数组
        private Color disapperColor; //背景色
        private Graphics gpPalette; //方块活动画板
        private Graphics gpReady; //下一个方块样式画板
        private BlockGroup bGroup; //方块生产机
        private Block runBlock; //正在活动的方块 
        private Block readyBlock; //下一个方块
        private int rectPix; //单元格像素
        private int _score = 0; //分数
        private System.Windows.Forms.TextBox tbScore;

        private System.Timers.Timer timerBlock; //定时器
        private int timeSpan = 800; //定时器时间间隔
        private int _lv = 1;
        public Palette(int x,int y,int pix,Color dColor,Graphics gp,Graphics gr, System.Windows.Forms.TextBox tb) //构造函数
        {
            _width = x;
            _height = y;
            coorArr = new Color[_width, _height];
            disapperColor = dColor;
            gpPalette = gp;
            gpReady = gr;
            rectPix = pix;
            tbScore = tb;
        }
        public void Start() //游戏开始
        {
            bGroup = new BlockGroup();
            runBlock = bGroup.GetABlock();
            runBlock.XPos = _width / 2;
            int y = 0;
            for (int i = 0; i < runBlock.Length; i++)
            {
                if(runBlock[i].Y > y)
                {
                    y = runBlock[i].Y;
                }
            }
            runBlock.YPos = y;
            gpPalette.Clear(disapperColor);//清空画板
            runBlock.Paint(gpPalette);//话运行方块
            Thread.Sleep(20);
            readyBlock = bGroup.GetABlock(); //去另一个方块付给readyBlock
            readyBlock.XPos = 2;
            readyBlock.YPos = 2;
            gpReady.Clear(disapperColor);
            readyBlock.Paint(gpReady);
            timerBlock = new System.Timers.Timer(timeSpan);
            timerBlock.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);
            timerBlock.AutoReset = true;
            timerBlock.Start();
        }
        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            CheckAndOverBlock();
            Down();
        }
        public bool Down() //向下移动
        {
            int xPos = runBlock.XPos;
            int yPos = runBlock.YPos + 1;
            for (int i = 0; i < runBlock.Length; i++)
            {
                if ((yPos - runBlock[i].Y) > (_height - 1))
                    return false; //超出下边界，失败
                if (!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)
                    return false; //遇到障碍物，失败
            }
            runBlock.erase(gpPalette);
            runBlock.YPos++;
            runBlock.Paint(gpPalette);
            return true;
        }
        public void Drop()
        {
            timerBlock.Stop();
            while (Down()) ;
            timerBlock.Start();
        }
        public void MoveLeft()
        {
            int xPos = runBlock.XPos - 1;
            int yPos = runBlock.YPos;
            for (int i = 0; i < runBlock.Length; i++)
            {
                if ((xPos + runBlock[i].X) < 0)
                    return; //超出下边界，失败
                if (!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)
                    return; //遇到障碍物，失败
            }
            runBlock.erase(gpPalette);
            runBlock.XPos--;
            runBlock.Paint(gpPalette);
        }
        public void MoveRight()
        {
            int xPos = runBlock.XPos + 1;
            int yPos = runBlock.YPos;
            for (int i = 0; i < runBlock.Length; i++)
            {
                if (xPos + runBlock[i].X > _width - 1)
                    return; //超出下边界，失败
                if (!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)
                    return; //遇到障碍物，失败
            }
            runBlock.erase(gpPalette);
            runBlock.XPos++;
            runBlock.Paint(gpPalette);
        }
        public void DeasilRotate() //顺时针旋转
        {
            for (int i = 0; i < runBlock.Length; i++)
            {
                int x = runBlock.XPos + runBlock[i].Y;
                int y = runBlock.YPos + runBlock[i].X;
                if (x < 0 || x > _width - 1) //超出左右边界，旋转失败
                    return;
                if (y < 0 || y > _height - 1) //超出上下边界，旋转失败
                    return;
                if (!coorArr[x, y].IsEmpty) //旋转后的位置有方块，旋转失败
                    return;
            }
            runBlock.erase(gpPalette);
            runBlock.DeasilRotate();
            runBlock.Paint(gpPalette);
        }
        public void ContraRotate() //逆时针旋转
        {
            for (int i = 0; i < runBlock.Length; i++)
            {
                int x = runBlock.XPos - runBlock[i].Y;
                int y = runBlock.YPos - runBlock[i].X;
                if (x < 0 || x > _width - 1) //超出左右边界，旋转失败
                    return;
                if (y < 0 || y > _height - 1) //超出上下边界，旋转失败
                    return;
                if (!coorArr[x, y].IsEmpty) //旋转后的位置有方块，旋转失败
                    return;
            }
            runBlock.erase(gpPalette);
            runBlock.ContraRotate();
            runBlock.Paint(gpPalette);
        }
        private void PaintBackGround(Graphics gp) //重画画板背景
        {
            gp.Clear(Color.Black); //先清空画板
            for (int i = 0; i < _height; i++)
            {
                for (int j = 0; j < _width; j++)
                {
                    if (!coorArr[j, i].IsEmpty)
                    {
                        SolidBrush sb = new SolidBrush(coorArr[j, i]);
                        gp.FillRectangle(sb, j * rectPix + 1,
                            i * rectPix + 1,
                            rectPix - 2,
                            rectPix - 2);
                    }
                }
            }
        }
        public void PaintPalette(Graphics gp) //重画整个画板
        {
            PaintBackGround(gp); //先画背景

            if (runBlock != null) //再画活动方块
            {
                runBlock.Paint(gp);
            }
        }
        public void PaintReady(Graphics gp) //重画下一个方块
        {
            if (readyBlock != null)
            {
                readyBlock.Paint(gp);
            }
        }
        public void CheckAndOverBlock() //检查方块是到底部。是则把当前方块归入coorArr，并产生新的方块。
        {
            bool over = false; //设置一个当前运行方块是否到底部的标志
            for(int i = 0;i < runBlock.Length; i++){
                int x = runBlock.XPos + runBlock[i].X;
                int y = runBlock.YPos - runBlock[i].Y;
                if (y == _height - 1) //到达下边界，则当前方块结束
                {
                    over = true;
                    break;
                }
                if (!coorArr[x, y + 1].IsEmpty) //与其他方块碰撞，则当前方块结束
                {
                    over = true;
                    break;
                }
            }
            if (over) //当前方块结束
            {
                for (int i = 0; i < runBlock.Length; i++) //把当前方块归入coorArr
                {
                    coorArr[runBlock.XPos + runBlock[i].X, runBlock.YPos - runBlock[i].Y] = runBlock.BlockColor;
                }
                //检查满行，满行则消除
                CheckAndDelFullRow();
                //产生新方块
                runBlock = readyBlock; //从准备区获取新方块
                runBlock.XPos = _width / 2; //确定当前运行方块的出生坐标
                int y = 0; //确定方块的yPos，确保新方块顶上没有空行
                for (int i = 0; i < runBlock.Length; i++)
                {
                    if (runBlock[i].Y > y)
                    {
                        y = runBlock[i].Y;
                    }
                }
                runBlock.YPos = y;
                //检查新产生的方块所占用的地方是否已被占用
                for (int i = 0; i < runBlock.Length; i++)
                {
                    if (!coorArr[runBlock.XPos + runBlock[i].X, runBlock.YPos - runBlock[i].Y].IsEmpty)
                    {   //Game Over
                        StringFormat drawFormat = new StringFormat();
                        drawFormat.Alignment = StringAlignment.Center;
                        gpPalette.DrawString("GAME OVER",
                            new Font("Arial Black", 25f),
                            new SolidBrush(Color.White),
                            new RectangleF(0, _height * rectPix / 2 - 100, _width * rectPix, 100),
                            drawFormat);
                        timerBlock.Stop();
                        return;
                    }
                }
                runBlock.Paint(gpPalette);
                //获取新的准备方块
                readyBlock = bGroup.GetABlock();
                readyBlock.XPos = 2;
                readyBlock.YPos = 2;
                gpReady.Clear(Color.Black);
                readyBlock.Paint(gpReady);
            }
        }
        private void CheckAndDelFullRow() //检查并删除满行
        {
            //算出当前方块所在行范围
            int lowRow = runBlock.YPos - runBlock[0].Y; //lowRow代表当前方块的y轴最小值
            int highRow = lowRow; //heighRow代表当前方块的y轴最大值
            for (int i = 1; i < runBlock.Length; i++)
            {   //算出当前方块所占行的范围，放入low、heigh变量内
                int y = runBlock.YPos - runBlock[i].Y;
                if (y < lowRow)
                {
                    lowRow = y;
                }
                if (y > highRow)
                {
                    highRow = y;
                }
            }
            bool repaint = false; //判断是否重画标志
            for (int i = lowRow; i <= highRow; i++)
            {   //检查满行，如果有满行，则删除这些满行
                bool rowFull = true;
                for (int j = 0; j < _width; j++) //判断满行
                {
                    if (coorArr[j, i].IsEmpty)
                    {
                        rowFull = false;
                        break;
                    }
                }
                if (rowFull) //满行，则删除这行
                {
                    repaint = true; //如果有删除的行，则需要重画
                    for (int k = i; k > 0; k--)
                    {
                        for (int j = 0; j < _width; j++)
                        {
                            coorArr[j, k] = coorArr[j, k - 1];
                        }
                    }
                    for (int j = 0; j < _width; j++) //清空第0行
                    {
                        coorArr[j, 0] = Color.Empty;
                    }
                    _score += 10;
                    SetText2(_score.ToString());
                    checkLevel();
                }
            }
            if (repaint) //重画
            {
                PaintBackGround(gpPalette);
            }
        }
        delegate void SafeSetText(string strMsg); //委托，设置得分
        private void SetText2(string strMsg)
        {
            SafeSetText objSet = delegate(string str)
            {
                tbScore.Text = str;
            };
            tbScore.Invoke(objSet,new object[]{strMsg});
        }
        public void Pause() //暂停
        {
            if (timerBlock.Enabled == true)
            {
                timerBlock.Enabled = false;
            }
        }
        public void EndPause() //结束暂停
        {
            if (timerBlock.Enabled == false)
            {
                timerBlock.Enabled = true;
            }
        }
        public void Close() //关闭
        {
            timerBlock.Close();
            gpPalette.Dispose();
            gpReady.Dispose();
        }
        private void checkLevel()
        {
            if (_score >= _lv * 100)
            {
                _lv++;
                timeSpan -= 10;
            }
        }
    }
}
